?android:selectableItemBackground
想要最快速度的给view加上点击效果,试试在xml中加上
android:background="?android:selectableItemBackground"
,Android5.0以上是波纹效果,5.0以下是普通的点击效果overridePendingTransition
overridePendingTransition
这个函数有两个参数,一个参数表示第一个activity进入时的动画,另外一个函数表示第二个activity退出时的动画,需要注意的是此方法需要在startActivity()或者finish()后调用,在切换或者退出时就会调用此动画
Uri结构
基本形式:
[scheme:]scheme-specific-part[#fragment]
这里分为三部分,分别是:scheme、scheme-specific-part、fragment
进一步划分:
[scheme:][//authority][path][?query][#fragment]
path可以有多个,每个用/连接,比如:
scheme:authority/path1/path2/path3?query#fragment
query参数可以带有对应的值,也可以不带,如果带对应的值用=表示,如:
scheme://authority/path1/path2/path3?id = 1#fragment
query参数可以有多个,每个用&连接
scheme://authority/path1/path2/path3?id = 1 & name = mingming & old#fragment
在android中,除了scheme、authority是必须的,其他的几个path、query、fragment,它们每一个都可以选择要或者不要,但顺序不能变
终极划分
其中authority又可以划分为host:port的形式:
[scheme:][//host:port][path][?query][#fragment]
本章节参考自文章Uri详解之——Uri结构与代码提取
选择图片、拍照以及图片裁剪
拍照
|
|
从相册选择照片
1234private void gotoPickImage() {Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);startActivityForResult(intent, REQUEST_PICK_IMAGE);}选择一张图片并裁剪获得一个小图
|
|
在将return-data
设为true
的时候,在onActivityForResult()
中可以直接通过data.getParcelableExtra("data")
得到裁剪后的Bitmap对象,但是当Bitmap过大时,就不能使用这种方式了,得使用下面这种方式。
MediaStore.EXTRA_OUTPUT
设置裁剪图片的输入Uri,可以通过Uri.formFile(tmpFile)
获得。
选择一张图片并裁剪获得一个大图
12345678910111213141516private void gotoPickAndCropBigBitmap() {imageUri = getTmpUri();Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);intent.setType("image/*");intent.putExtra("crop", "true");intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);intent.putExtra("outputX", 2000);intent.putExtra("outputY", 2000);intent.putExtra("scale", true);intent.putExtra("return-data", false);intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());intent.putExtra("noFaceDetection", true); // no face detectionstartActivityForResult(intent, REQUEST_CROP_IMAGE_BIG);}这里把
return-data
设为false
,同时向MediaStore.EXTRA_OUTPUT
设置一个临时构造的Uri
,这个Uri
用来保存裁剪后的大图,裁剪之后,在onActivityForResult()
中就可以通过MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri)
得到裁剪后的Bitmap大图。拍照并裁剪
|
|
这一部分其实分为了两步,第一步拍照得到图片的Uri,第二步把该图片的Uri传给裁剪图片的程序处理:
- 这里的action变成了
com.android.camera.action.CROP
,并且不需要设置extra
字段`crop`` `intent.setDataAndType(uri, "image/*")
,这里的uri指向拍照后得到的原图,intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
将裁剪后的图片也保存在这个uri,所以原图就被覆盖了本章节转载自文章。
getCahceDir()
、getFilesDir()
、getExternalFilesDir()
和getExternalCacheDir()
getCacheDir()
方法获取/data/data//cache目录
getFilesDir()
方法获取/data/data//files
目录通过
Context.getExternalFilesDir()
方法获取到SDCard/Android/data/你的应用的包名/files/
目录,一般放一些长时间保存的数据
通过
Context.getExternalCacheDir()
方法获取到SDCard/Android/data/你的应用的包名/cache/
目录,一般存放临时缓存数据当使用
Context.getExternalFilesDir()
和Context.getExternalCacheDir()
方法时,当你的应用被卸载后,SDCard/Android/data/你的应用的包名/
这个目录下的所有文件都会被删除,不会留下垃圾信息。较优秀的程序都会专门写一个方法来获取缓存地址:
|
|
可以看到,当SD卡存在或者SD卡不可被移除的时候,就调用getExternalCacheDir()
方法来获取缓存路径,否则就调用getCacheDir()方法来获取缓存路径。前者获取到的就是/sdcard/Android/data//cache
这个路径,而后者获取到的是/data/data//cache
这个路径。
注意:这两种方式的缓存都会在卸载app的时候被系统清理到,而开发者自己在sd卡上建立的缓存文件夹,是不会跟随着app的卸载而被清除掉的。
Glide的
crossFade()
方法无论你是在加载图片之前是否显示一个占位符,改变 ImageView 的图片在你的 UI 中有非常显著的变化。一个简单的选项是让它改变是更加平滑和养眼的,就是使用一个淡入淡出动画。Glide 使用标准的淡入淡出动画,这是(对于当前版本3.6.1)默认激活的。如果你想要如强制 Glide 显示一个淡入淡出动画,你必须调用另外一个建造者:
123456Glide.with(context).load(UsageExampleListViewAdapter.eatFoodyImages[0]).placeholder(R.mipmap.ic_launcher) // can also be a drawable.error(R.mipmap.future_studio_launcher) // will be displayed if the image cannot be loaded.crossFade().into(imageViewFade);crossFade()
方法还有另外重载方法crossFade(int duration)
。如果你想要去减慢(或加快)动画,随时可以传一个毫秒的时间给这个方法。动画默认的持续时间是 300毫秒。本章节转载自文章glide的基本使用以及原理
FragmentPagerAdapter和FragmentPagerStateAdapter
FragmentPagerAdapter
FragmentPagerAdapter继承自PagerAdapter,是专门给ViewPager进行数据适配的,FragmentPagerAdapter这个适配器是用来实现Fragment在ViewPager里面进行滑动切换的,FragmentPagerAdapter拥有自己的缓存策略,当和ViewPager配合使用的时候,会缓存当前Fragment以及左边一个、右边一个一共三个Fragment对象。
假如有三个Fragment,那么在ViewPager初始化之后,三个fragment都会加载完成,中间的Fragment在整个生命周期里只会加载一次,当最左边的Fragment处于显示状态,最右边的Fragment由于超出缓存范围,会被销毁,当再次滑到中间的Fragment时,最右边的Fragment会被再次初始化。
因此,FragmentPagerAdapter最适合来做固定的较少数量的场合,比如说一个有3个tab标签的fragment滑动界面,FragmentPagerAdapter会对我们浏览过的Fragment进行缓存,保存这些界面的临时状态,这样当我们左右滑动的时候,界面切换会更加的流畅,但是这样也会增加程序占用的内存,如果应用场景是更多的Fragment,请使用FragmentStatePagerAdapter。
FragmentPagerStateAdapter
FragmentPagerStateAdapter也是PagerAdapter的子类,它的工作方式和ListView相似,当Fragment对用户不可见的时候,整个Fragment会被销毁,只会保存Fragment的保存状态,基于这样的特性,FragmentPagerStateAdapter比FragmentPagerAdapter更适合于用于很多界面之间的切换,而且消耗更少的内存资源
本章节转载自文章FragmentPagerAdapter与FragmentStatePagerAdapter使用详解与区别
CoordinatorLayout与滚动的处理
浮动操作按钮
CoordinatorLayout可以用来配合浮动操作按钮的
layout_anchor
和layout_gravity
属性制造出浮动效果,layout_anchor
指定参照物,anchorGravity
指定相对于参照物的位置,设置为bottom | right则表示将FloatingActionButton放置于参照物的右下角:
|
|
Toolbar的扩展和收缩
12345678910111213141516171819202122<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/main_content"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"><android.support.design.widget.AppBarLayoutandroid:id="@+id/appbar"android:layout_width="match_parent"android:layout_height="@dimen/detail_backdrop_height"android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"android:fitsSystemWindows="true"><android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /></android.support.design.widget.AppBarLayout></android.support.design.widget.CoordinatorLayout>需要注意的是AppBarLayout目前必须是第一个嵌套在CoordinatorLayout里面的子View。
然后我们需要定义AppBarLayout与滚动视图之间的联系,在RecyclerView或者任意支持嵌套滚动的View比如NestedScrollView上添加
app:layout_behavior
,support library包含了一个特殊的字符串资源@string/appbar_scrolling_view_behavior
,它的值为android.support.design.widget.AppBarLayout$ScrollingViewBehavior
,指向AppBarLayout.ScrollingViewBehavior,用来通知AppBarLayout这个特殊的view何时发生了滚动事件,这个behavior需要设置在触发滚动事件的view之上。12345<android.support.v7.widget.RecyclerViewandroid:id="@+id/rvToDoList"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/appbar_scrolling_view_behavior">当CoordinatorLayout发现RecyclerView中设置了这个属性,它会搜索自己所包含的其他view,看看是否有view与这个behavior相关联,AppBarLayout.ScrollingViewBehavior描述了RecyclerView与AppBarLayout之间的依赖关系,RecyclerView的任意滚动事件都将触发AppBarLayout或者AppBarLayout里面view的改变。
AppBarLayout里面定义的view只要设置了
app:layout_scrollFlags
属性,就可以在RecyclerView滚动事件发生时被触发:12345678910111213<android.support.design.widget.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:fitsSystemWindows="true"android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"><android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"app:layout_scrollFlags="scroll|enterAlways"/></android.support.design.widget.AppBarLayout>app:layout_scrollFlags
这个属性必须至少启动scroll这个flag,这样这个view才会滚出屏幕,否则它将一直固定在顶部,可以使用的其他flag有:- enterAlways: 一旦向上滚动这个view就可见
- enterAlwaysCollapsed: 这个flag定义的是何时进入(已经消失之后何时再次显示),假设你定义了一个最小高度(minHeight),同时enterAlways也定义了,那么view将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完
- exitUntilCollapsed: 这个flag定义何时退出,当你定义了一个minHeight,这个view将在滚动到这个最小高度的时候消失
制造折叠效果
如果想制造Toolbar的折叠效果,必须把ToolBar放在CollapsingToolbarLayout中:
|
|
需要注意的是通常我们都是设置ToolBar的Title,而现在,需要将title设置在CollapsingToolbarLayout上,而不是ToolBar:
|
|
制造视觉效果
CollapsingToolbarLayout还能让我们做出更高级的动画,比如在里面放一个ImageView,然后在它折叠的时候渐渐淡出。同时在用户滚动的时候title的高度也会随着改变。
为了制造出这种效果,我们添加一个定义了app:layout_collapseMode=”parallax” 属性的ImageView。
123456789101112131415161718192021222324<android.support.design.widget.CollapsingToolbarLayoutandroid:id="@+id/collapsing_toolbar"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"app:contentScrim="?attr/colorPrimary"app:expandedTitleMarginEnd="64dp"app:expandedTitleMarginStart="48dp"app:layout_scrollFlags="scroll|exitUntilCollapsed"><android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"app:layout_scrollFlags="scroll|enterAlways"></android.support.v7.widget.Toolbar><ImageViewandroid:src="@drawable/cheese_1"app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"android:layout_width="wrap_content"android:layout_height="wrap_content"android:scaleType="centerCrop"app:layout_collapseMode="parallax"android:minHeight="100dp"/></android.support.design.widget.CollapsingToolbarLayout>本章节转载自文章[CoordinatorLayout与滚动的处理(http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0717/3196.html)
定义数组
Android中可以在res->values->array.xml文件中声明数组,例如:
|
|
然后在代码中就可以通过如下方式获取数组:
|
|
ButterKnife的简单实用
要在代码中使用ButterKnife,首先需要在gradle中进行配置:
12compile 'com.jakewharton:butterknife:8.5.1'annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'需要注意的是加在
Module:app
的gradle文件中,加入之后直接同步一下即可,就可在External Libraries文件夹下看到ButterKnife为了在代码中使用ButterKnife,需要在代码中对ButterKnife服务进行注册:
12ButterKnife.bind(this); // 在Activity中使用ButterKnife.bind(this, view); // 在非Activity中使用绑定View控件
1234(R.id.btn_login)Button mBtn; // 单个View控件的绑定({R.id.first_name, R.id.middle_name, R.id.last_name})List<EditText> nameViews; // 多个控件的绑定可以写在List或者Array中资源绑定
12345678(R.string.title)String title;(R.drawable.graphic)Drawabel graphic;(R.color.red)int red;(R.dimen.spacer)Float spacer;监听器绑定
监听器可以直接注解到方法上
1234(R.id.submit)public void submit(View view) {}多个控件可以绑定到同一个监听器
1234({R.id.submit, R.id.login})public void sayHi(Button button) {button.setText("Hello");}当ButterKnife在Fragment的onCreateView()方法中进行绑定时,需要在onDestroyView()中进行解绑,ButterKnife.bind()方法提供了一个Unbinder返回值,在onDestroyView()中调用相关的unbind()方法即可:
123456789101112131415public class FancyFragment extends Fragment {(R.id.button1) Button button1;(R.id.button2) Button button2;private Unbinder unbinder;public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fancy_fragment, container,false);unbinder = ButterKnife.bind(this, view);// TODO Use fields...return view;}public void onDestroyView() {super.onDestroyView();unbinder.unbind();}}- 本章节转载自文章Butterknife 使用指南
ActionBar
setHomeButtonEnabled
这个在小于4.0版本的默认值是true,但是在4.0及其以上是false,该方法的作用是决定左上角的图标是否可以点击,没有向左的小图标,true图标可以点击,false图标不可点击setDisplayHomeAsUpEnabled(true)
:给左上角图标的左边加上一个返回的图标,对应ActionBar.DISPLAY_HOME_AS_UP
setDisplayShowHomeEnabled(true)
:使左上角图标是否显示,如果设为false,则没有程序图标,仅仅就是个标题,否则,显示应用程序图标,对应id为Android.R.id.home
,对应ActionBar.DISPLAY_SHOW_HOME
setDispalyShowTitleEnabled(true)
:对应ActionBar.DISPLAY_SHOW_TITLE
setHomeButtonEnabled
和setDisplayShowHomeEnabled(true)
共同起作用,如果setHomeButtonEnabled
设为false,即使setDisplayShowHomeEnabled(true)
设为true,图标也不能点击如果希望点击图标左侧箭头返回上一页,需要加载选项菜单后,对于菜单项的点击事项调用如下方法:
|
|
在实际项目开发过程中,通常为所有的
Activity
定义一个BaseActivity
,可以在BaseActivity
中定义:private Activity mActivity;
,这样在onCreate()
方法中定义mActivity= this
,那么子类在继承BaseActivity时在onCreate()
方法中通过super.onCreate()
方法可以执行BaseActivity的onCreate()
方法中的代码,即执行了mActivity = this
,那么此时的mActivity
也就代表了当前的Activity
。如果想在项目中使用
CardView
,需要在build.gradle
文件中添加下面的代码:12//卡片式布局compile 'com.android.support:cardview-v7:24.1.1'如果想在项目中使用
Glide
,需要在build.gradle
文件中添加下面的代码:12//图片加载框架 Glidecompile 'com.github.bumptech.glide:glide:3.7.0'Android ListView与适配器模式
电源适配器相信大家都知道,其作用就是将插座的220V电源转换为电脑所需要的5V电源,在软件开发中,我们称之为接口不兼容,此时就需要适配器来进行接口转换。
因此,适配器模式就是把一个类的接口变成客户端所期待的另外一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。
适配器模式通常涉及到Target、Adapter和Adaptee三部分,Target就是客户端所期望的接口,Adaptee就是需要适配的接口,而Adapter就用来将Adaptee接口转换成Target接口。
适配器模式可以分为类适配器模式和对象适配器模式。
类适配器模式
此时Adapter类需要继承Adaptee并且实现Target接口,在Adapter类中实现的Target接口方法中调用Adaptee中的方法:
12345678910111213141516171819202122// Targetpublic interface Target {public void target();}// Adapteepublic class Adaptee() {public void adaptee() {System.out.println("adaptee...");}}// Adapterpublic class Adapter extends Adaptee implements Target {public void target() {convertFromAdapteeToTarget();}private void convertFromAdapteeToTarget() {}}对象适配器模式
与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用代理关系连接到Adaptee类。
1234567891011121314151617181920212223242526272829// Targetpublic interface Target {public void target();}// Adapteepublic class Adaptee() {public void adaptee() {System.out.println("adaptee...");}}// Adapterpublic class Adapter implements Target {private Adaptee adaptee;public void setAdaptee(Adaptee adaptee) {this.adaptee = adaptee;}public void target() {convertFromAdapteeToTarget();}private void convertFromAdapteeToTarget() {}}建议尽量使用对象适配器的实现方式,多用合成/聚合,少用继承。
下面看看Android中的ListView是如何使用适配器模式的,首先看一下使用ListView的代码:
|
|
那么为什么这里需要使用Adapter模式呢?我们知道,ListView需要能够显示各种各样的视图,每个人需要的显示效果不相同,显示的数据类型、数量也各不相同,那么如何隔离这种变化就很重要!
Android中的做法是增加一个Adapter层来应对变化,将ListView需要的接口抽象到Adapter对象中,这样只要用户实现了Adapter接口,ListView就可以按照用户设定的显示效果、数量、数据来显示特定的item view。
通过代理数据集来告知ListView数据的个数( getCount函数 )以及每个数据的类型( getItem函数 ),最重要的是要解决Item View的输出。Item View千变万化,但终究它都是View类型,Adapter统一将Item View输出View ( getView函数 ),这样就很好的应对了Item View的可变性。
那么ListView是如何通过Adapter模式 ( 不止Adapter模式 )来运作的呢 ?我们一起来看一看。 ListView继承自AbsListView,Adapter定义在AbsListView中,我们看一看这个类。
|
|
AbsListView定义了集合视图的框架,比如Adapter模式的应用、复用Item View的逻辑、布局Item View的逻辑等。子类只需要覆写特定的方法即可实现集合视图的功能,例如ListView。
ListView中相关方法:
|
|
ListView覆写了AbsListView中的layoutChilden函数,在该函数中根据布局模式来布局Item View。Item View的个数、样式都通过Adapter对应的方法来获取,获取个数、Item View之后,将这些Item View布局到ListView对应的坐标上,再加上Item View的复用机制,整个ListView就基本运转起来了。
当然这里的Adapter并不是经典的适配器模式,但是却是对象适配器模式的优秀示例,也很好的体现了面向对象的一些基本原则。这里的Target角色和Adapter角色融合在一起,Adapter中的方法就是目标方法;而Adaptee角色就是ListView的数据集与Item View,Adapter代理数据集,从而获取到数据集的个数、元素。
通过增加Adapter一层来将Item View的操作抽象起来,ListView等集合视图通过Adapter对象获得Item的个数、数据元素、Item View等,从而达到适配各种数据、各种Item视图的效果。因为Item View和数据类型千变万化,android师们将这些变化的部分交给用户来处理,通过getCount、getItem、getView等几个方法抽象出来,也就是将Item View的构造过程交给用户来处理,灵活地运用了适配器模式,达到了无限适配、拥抱变化的目的。
本章节转载自文章Android源码之ListView的适配器模式。
FrameLayout的特点就是FrameLayout中的多个布局会重叠显示,看下面这段代码:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"><android.support.v7.widget.Toolbarandroid:id="@+id/tb_joke"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="?attr/colorPrimary"android:fitsSystemWindows="true"android:titleTextColor="#fff"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_joke_title"/></android.support.v7.widget.Toolbar><FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:id="@+id/ll_loading"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"android:visibility="visible"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="正在加载中"/></LinearLayout><LinearLayoutandroid:visibility="gone"android:id="@+id/ll_error"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="加载失败"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:clickable="true"android:id="@+id/tv_joke_load_again"android:background="#d7d6d6"android:padding="10dp"android:text="重新加载"/></LinearLayout><android.support.v4.widget.SwipeRefreshLayoutandroid:id="@+id/srl_joke"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v7.widget.RecyclerViewandroid:id="@+id/rv_joke"android:layout_width="match_parent"android:layout_height="match_parent"></android.support.v7.widget.RecyclerView></android.support.v4.widget.SwipeRefreshLayout></FrameLayout></LinearLayout>在FrameLayout中包含了3个子布局,即两个LinearLayout和一个SwipeRefreshLayout,三者会重叠显示,那么在代码中通过控制各个不同的布局在不同情况下的显示和消失就可以显示几种不同的布局。
android:imeOptions
属性默认情况下软键盘右下角按钮为“下一个”,点击会进入到下一个输入框,保持软键盘,设置
android:imeOptions=actionDone
,软键盘下方变成完成,点击后光标保持在原来的输入框中,并且软键盘关闭,设置android:imeOptions=actionSend
软键盘下方变成“发送”,点击后光标移动到下一个,那么设置的imeOptions如何使用呢?一般情况下可以这样使用:让EditText实现OnEditorActionListener
,在onEditActin
方法中actionId就对应我们设置的imeOptions,系统默认的actionId有EditorInfo.IME_NULL
、EditorInfo.IME_ACTION_SEND
、EditorInfo.IME_ACTION_DONE
,这样就可以根据不同的EditText实现不同的软键盘右下角功能键:
|
|
android:clipToPadding
的作用常常用于paddingTop的情况,并且默认情况下其值为true,当内部有个属性设置了paddingTop但是滑动的时候就忽视paddingTop则可以设置
android:clipToPadding="false"
。大家可以参考 Padding与绘制区域–android:clipToPadding和android:clipChildren这篇文章,看了图就懂了!
另外再推荐一篇文章android:clipToPadding属性应用,这篇文章讲的蛮好的,其效果图如下:
android:clipToPadding="true"
android:clipToPadding="false"
Java中indexOf方法
indexOf()方法用于在字符串中查找子串,该方法返回一个整数,指出String对象内子字符串的开始位置,如果没有找到该子串,则返回-1。
indexof()方法的函数原型如下:
|
|
Android在实现界面刷新时有两种方法
invalidate
和postInvalidate
,两者的区别在于invalidate
方法不能直接在线程中调用,必须在UI线程中调用,而postInvalidate
可以在工作线程中调用。设置画笔属性
setAntiAlias(boolean aa)
打开抗锯齿,抗锯齿是依赖于算法的,算法决定抗锯齿的效率,我们在绘制棱角分明的图像时,比如一个矩形、一张位图,我们不需要打开抗锯齿
setColorFilter(ColorFilter filter)
这个方法需要传入一个
ColorFilter
参数同样也会返回一个ColorFilter
实例,其实ColorFilter
类是一个父类,其有3个子类,分别为ColorMatrixColorFilter
、LightingColorFilter
和PorterDuffColorFilter
。ColorMatrixColorFilter
色彩矩阵颜色过滤器,在Android中图片是以RGBA像素点的形式加载到内存中的,修改这些像素信息需要一个叫做
ColorMatrix
类的支持,其定义了一个4*5
的float[]
类型的矩阵:123456ColorMatrix colorMatrix = new ColorMatrix(new float[]{1, 0, 0, 0, 0,0, 1, 0, 0, 0,0, 0, 1, 0, 0,0, 0, 0, 1, 0,});第一行表示的R(红色)的向量,第二行表示的G(绿色)的向量,第三行表示的B(蓝色)的向量,最后一行表示A(透明度)的向量。这个矩阵不同的位置表示的RGBA值,其范围在0.0F至2.0F之间,1为保持原图的RGB值。每一行的第五列数字表示偏移值,何为偏移值?顾名思义当我们想让颜色更倾向于红色的时候就增大R向量中的偏移值,想让颜色更倾向于蓝色的时候就增大B向量中的偏移值。
通过修改
ColorMatrix
,我们可以修改颜色,比如:12345678// 生成色彩矩阵ColorMatrix colorMatrix = new ColorMatrix(new float[]{0.5F, 0, 0, 0, 0,0, 0.5F, 0, 0, 0,0, 0, 0.5F, 0, 0,0, 0, 0, 1, 0,});mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));这其中的原理是这样的:
LightingColorFilter
光照颜色过滤,这个方法只有一个构造方法:
1LightingColorFilter(int mul, int add);其中
mul
全称是colorMultiply即色彩倍增,而add全称是colorAdd即色彩增加,这两个值都是16进制的0xAARRGGBB。PorterDuffColorFilter
PorterDuffColorFilter
只有一个构造方法:1PorterDuffColorFilter(int color, PorterDuff.Mode mode);这个构造方法也接受两个值,一个是16进制表示的颜色值这个很好理解,而另一个是
PorterDuff
内部类Mode中的一个常量值,这个值表示混合模式。那么什么是混合模式呢?混合混合必定是有两种东西混才行,第一种就是我们设置的color值而第二种当然就是我们画布上的元素了!,比如这里我们把Color的值设为红色,而模式设为PorterDuff.Mode.DARKEN
变暗:
ViewConfiguration.getScaledTouchSlop()
getScaledTouchSlop
是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件,如viewpager就是用这个距离来判断用户是否翻页Android中全局Application的onCreate()方法多次调用问题
通常,一个应用的所有组件都运行在系统为这个应用所创建的默认进程中,这个默认进程是用这个应用的包名来命名的,如果声明文件中的组件或应用没有指定这个属性则默认应用和其组件将相应运行在以其包名命名的进程中。
一般来说,Application的onCreate()方法只会执行一次,如果应用中采用多进程方式,onCreate()方法会执行多次,根据不同的进程名字进行不同的初始化。
一般情况下一个服务没有自己独立的进程,它一般是作为一个线程运行于它所在的应用的进程中,但是也有例外,Android声明文件中的
android:process
属性却可以为任意组件包括应用指定进程,即通过在声明文件中设置android:process
属性,我们可以让组件(例如Activity、Service)和应用(Application)创建并运行于我们指定的进程中,冒号(”:”)这个前缀将把这个名字附加到你的包所运行的标准进程名字的后面作为新的进程名称:123<service android:name="com.baidu.location.f"android:enabled="true"android:process=":baiduMap"></service>那么在DDMS中就可以看到这个进程:
com.example.hello:baiduMap
。解决方法是在自定义的Application的onCreate方法中控制不同进程的初始化:
12345678910111213141516171819202122232425262728String processName = getProcessName(this, android.os.Process.myPid());if (processName != null) {boolean defaultProcess = processName.equals(Constants.REAL_PACKAGE_NAME);// 默认的主进程启动时初始化应用if (defaultProcess) {initAppForMainProcess();}// 其他进程启动时初始化对应内容else if (processName.contains(":webbrowser")) {} else if (processName.contains(":wallet")) {}}public static String getProcessName(Context cxt, int pid) {ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);List<RunningAppP.rocessInfo> runningApps = am.getRunningAppProcesses();if (runningApps == null) {return null;}for (RunningAppProcessInfo procInfo : runningApps) {if (procInfo.pid == pid) {return procInfo.processName;}}return null;}本小节转载自文章Android中全局Application的onCreate多次调用问题。
Java静态方法可以被重写吗?
非静态方法属于类的实例,是可以被子类重写从而达到多态的效果,静态方法属于类,是不能被重写,故而不能实现多态。
compileSdkVersion
表示编译版本,就是运行我们这个项目的SDK版本号,也就是API Level,例如API-19、API-20等
buildToolVersion
表示构建工具的版本,其中包含了打包工具aapt、dx等等,这个工具的目录位于..your_sdk_path/build_tools/xx.xx.xx
minSdkVersion
指定应用程序所需的最小API Level,如果不指明的话默认为1,也就是说该应用兼容所有的android版本,我们应该总是声明这个属性。
如果系统的API Level低于minSdkVersion,那么android系统会阻止用户安装这个应用。
如果指明了这个属性,并且在项目中使用了高于这个API Levle的API,那么在编译时就会报错。
因此,minSdkVersion不仅在安装程序时起作用,也会在项目构建时起作用。
targetSdkVersion
targetSdkVersion是Android系统提供向前兼容的主要手段,随着Android系统的升级,某个系统的API或者模块的行为可能会发生变化,但是为了保证老APK的行为还是和以前兼容,只要targetSdkVersion不变,即使这个APK安装在新Android系统上,其行为还是保持老的系统上的行为,这样就保证了系统对老应用的向前兼容性。
在 Android 4.4 (API 19)以后,AlarmManager 的 set() 和 setRepeat() 这两个 API 的行为发生了变化。在 Android 4.4 以前,这两个 API 设置的都是精确的时间,系统能保证在 API 设置的时间点上唤醒 Alarm。因为省电原因 Android 4.4 系统实现了 AlarmManager 的对齐唤醒,这两个 API 设置唤醒的时间,系统都对待成不精确的时间,系统只能保证在你设置的时间点之后某个时间唤醒。
这时,虽然 API 没有任何变化,但是实际上 API 的行为却发生了变化,如果老的 APK 中使用了此 API,并且在应用中的行为非常依赖 AlarmManager 在精确的时间唤醒,例如闹钟应用。如果 Android 系统不能保证兼容,老的 APK 安装在新的系统上,就会出现问题。
Android 系统是怎么保证这种兼容性的呢?这时候 targetSdkVersion 就起作用了。APK 在调用系统 AlarmManager 的 set() 或者 setRepeat() 的时候,系统首先会查一下调用的 APK 的 targetSdkVersion 信息,如果小于 19,就还是按照老的行为,即精确设置唤醒时间,否者执行新的行为。
本小节转载自文章Android targetSdkVersion 原理。